<!--
 * 字段组
 * @作者: 陈老师儿~
 * @手机: 18560000860
 -->
<template>
    <form class="pure-form" :class="classes" :style="styles">
        <slot></slot>
    </form>
</template>

<script>
    import props from "./props.js";
    import { computed } from "vue";
    import Schema from "async-validator";
    export default {
        options: {
            // 将自定义节点设置成虚拟的
            // 头条、飞书：因为合并后丢失事件和 'provide/inject'
            // 京东：因为合并后不能合并外层 'class'
            // 百度：因为合并后会在控制台疯狂报警告
            // #ifndef MP-TOUTIAO || MP-LARK || MP-JD || MP-BAIDU
            virtualHost: true,
            // #endif

            // 组件样式隔离
            styleIsolation: "apply-shared",

            // 允许使用多个插槽
            multipleSlots: true,
        },
        props: props,
        data() {
            return {
                // 默认数据
                originalFormData: {},
                // 字段单独配置的规则
                fieldRules: {},
                // 错误信息
                errors: [],
            };
        },
        computed: {
            // classes
            classes() {
                const classes = [];
                return classes;
            },

            // styles
            styles() {
                const styles = [];
                return styles;
            },

            // 最终的验证规则
            finallyRules() {
                // 合并字段单独配置的规则和全局配置的规则
                const rules = { ...this.rules, ...this.fieldRules };
                return rules;
            },
        },
        watch: {
            // 监听默认值
            defaultForm: {
                handler() {
                    // 设置默认值
                    this.setOriginalFormData();
                },
                deep: true,
            },
        },
        mounted() {
            // 设置默认值
            this.setOriginalFormData();
        },
        methods: {
            // 设置默认值
            setOriginalFormData() {
                this.originalFormData = this.deepClone(this.defaultForm || this.form || {});
            },

            // 更新字段单独配置的规则
            updateFieldRules(name, rules) {
                this.fieldRules[name] = rules;
            },

            // 验证整个表单
            validate(callback = () => {}) {
                // descriptor 验证规则
                const descriptor = this.finallyRules;

                // 验证器
                const validator = new Schema(descriptor);

                // options 验证选项
                const options = {
                    first: this.first, // 第一个未通过校验的字段发生错误就调用 callback，即不再继续校验剩余字段
                    firstFields: this.firstFields, // 每个字段的第一个规则发生错误就调用 callback，即不再继续校验该字段的剩余规则
                    suppressWarning: this.suppressWarnings, // 是否禁止无效值的内部警告
                };

                // 验证表单数据
                validator.validate(this.form, options, (errors, fields) => {
                    this.errors = errors;
                    callback(errors, fields);
                });
            },

            // 验证一个或多个字段
            validateField(fields, callback = () => {}) {
                // descriptor 验证规则
                const descriptor = {};

                // 需要验证的字段
                const fieldNames = Array.isArray(fields) ? fields : [fields];

                // 遍历需要验证的字段
                for (const fieldName of fieldNames) {
                    // 获取字段的验证规则
                    const fieldRules = this.finallyRules[fieldName];
                    if (fieldRules) {
                        // 有验证规则
                        descriptor[fieldName] = fieldRules;
                    }
                }

                // options 验证选项
                const options = {
                    first: this.first, // 第一个未通过校验的字段发生错误就调用 callback，即不再继续校验剩余字段
                    firstFields: this.firstFields, // 每个字段的第一个规则发生错误就调用 callback，即不再继续校验该字段的剩余规则
                    suppressWarning: this.suppressWarnings, // 是否禁止无效值的内部警告
                };

                // 验证器
                const validator = new Schema(descriptor);

                // 验证字段
                validator.validate(this.form, options, (errors, fields) => {
                    if (errors?.length > 0) {
                        // 遍历错误信息
                        for (const error of errors) {
                            // 查找是否已有该字段的错误信息
                            const index = this.errors.findIndex((item) => item.field === error.field);
                            if (index === -1) {
                                // 没有该字段的错误信息
                                this.errors.push(error);
                            } else {
                                // 已有该字段的错误信息
                                this.errors[index] = error;
                            }
                        }
                    } else {
                        // 没有错误信息
                        // 删除已有的错误信息
                        for (const fieldName of fieldNames) {
                            const index = this.errors.findIndex((item) => item.field === fieldName);
                            if (index !== -1) {
                                this.errors.splice(index, 1);
                            }
                        }
                    }
                    callback(errors, fields);
                });
            },

            // 重置表单
            reset() {
                // 重置表单数据
                return this.deepClone(this.originalFormData);
            },

            // 深克隆对象或数组
            deepClone(target) {
                // 如果目标是 null 或者不是对象类型，直接返回目标本身
                if (target === null || typeof target !== "object") {
                    return target;
                }

                let clone;
                // 判断目标是数组还是对象
                if (Array.isArray(target)) {
                    // 如果是数组，创建一个新的空数组
                    clone = [];
                    // 遍历数组的每个元素
                    for (let i = 0; i < target.length; i++) {
                        // 递归调用 deepClone 函数克隆每个元素
                        clone[i] = this.deepClone(target[i]);
                    }
                } else {
                    // 如果是对象，创建一个新的空对象
                    clone = {};
                    // 遍历对象的每个属性
                    for (let key in target) {
                        if (target.hasOwnProperty(key)) {
                            // 递归调用 deepClone 函数克隆每个属性的值
                            clone[key] = this.deepClone(target[key]);
                        }
                    }
                }
                return clone;
            },
        },
        provide() {
            return {
                // 表单全局验证规则
                formRules: computed(() => this.finallyRules),
                // 表单全局错误信息
                formErrors: computed(() => this.errors),
                // 表单全局验证时机
                formValidateTrigger: computed(() => this.validateTrigger),
                // 更新字段单独配置的规则
                updateFieldRules: this.updateFieldRules,
                // 验证表单字段
                formValidateField: this.validateField,
                // 表单全局必填符号文本
                formRequiredText: computed(() => this.requiredText),
                // 只读整个表单
                formReadonly: computed(() => this.readonly),
                // 禁用整个表单
                formDisabled: computed(() => this.disabled),
                // 表单全局禁用样式
                formDisabledClass: computed(() => this.disabledClass),
            };
        },
        expose: ["validate", "validateField", "reset"],
    };
</script>

<style scoped>
    @import "./style.css";
</style>
